use std::{sync::{Condvar, Mutex}, time::Instant};

pub use error::CustomError;

use ffmpeg::{av_fifo_alloc2_safe, av_packet_alloc_safe};
use ffmpeg_sys_next::{
    AV_FIFO_FLAG_AUTO_GROW, AVCodecContext, AVFifo, AVFormatContext, AVPacket, SwrContext,
};


pub mod media_player;
pub use media_player::*;

pub mod video_player;
use sdl2::{VideoSubsystem, audio::AudioDevice};
pub use video_player::*;

pub mod audio_player;
pub use audio_player::*;

pub mod timer;
pub use timer::*;

pub mod broadcast;
pub use broadcast::*;

pub mod error;
pub mod logger;

pub const MAX_AUDIO_FRAME_SIZE: i32 = 19200;
pub const MAX_QUEUE_SIZE: usize = 100;
pub const MIN_QUEUE_SIZE: usize = 2;
pub const MAX_FRAME_SIZE: usize = 5;

#[derive(Debug)]
pub struct MediaStatus {
    pub status: Mutex<PlayStatus>,
    pub condvar: Condvar,
}

impl MediaStatus {
    pub fn new() -> Self {
        MediaStatus { 
            status: Mutex::new(PlayStatus::new()), 
            condvar: Condvar::new(), 
        }
    }

    pub fn check_pause(&self) -> Result<bool, CustomError> {
        let status_lock = self.status.lock().unwrap();
        if (*status_lock).pause() {
            let _unused = self.condvar.wait(status_lock).unwrap();
        }
        return Ok(true);
    }

    pub fn pause_or_resume(&self) -> Result<Option<Instant>, CustomError> {
        let mut status_lock = self.status.lock().unwrap();
        println!("{:?}", status_lock);
        if (*status_lock).resume() {
            (*status_lock).set_pause();
            return Ok(Some(Instant::now()));
        } else {
            (*status_lock).set_resume();
            let _ = self.condvar.notify_all();
        }
        return Ok(None);
    }

    pub fn audio_check_status(&self, device: &AudioDevice<SquareWave>) -> Result<(), CustomError> {
        let mut play_status = self.status.lock().unwrap();
        if play_status.pause() {
            device.pause();
            play_status = self.condvar.wait(play_status).unwrap();
        }
        if play_status.resume() {
            device.resume();
        }
        Ok(())
    }
}

/**
 * 状态枚举值：end, forword, resume, pause, video_frame_end, audio_frame_end, packet_end, start
 * 从左到右按位
 * 左一位   1：开始；0：暂停
 * 左二位   1：读packet结束
 * 左三位   1：音频frame解密结束
 * 左四位   1：视频frame解密结束
 * 左五位   1：快退、快进
 * 左六位   1：播放结束
 */
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PlayStatus {
    pub status: u8,
}

impl PlayStatus {
    pub fn new() -> Self {
        PlayStatus { status: 1 }
    }

    pub fn pause(&self) -> bool {
        //println!("pause: {:?}", (self.status | 0b0) == 0);
        (self.status | 0b0) == 0
    }

    pub fn resume(&self) -> bool {
        //println!("resume: {:?}", (self.status & 0b1) == 1);
        (self.status & 0b1) == 1
    }

    pub fn packet_end(&self) -> bool {
        (self.status & 0b10) == 0b10
    }

    pub fn audio_frame_end(&self) -> bool {
        (self.status & 0b100) == 0b100
    }
    
    pub fn video_frame_end(&self) -> bool {
        (self.status & 0b1000) == 0b1000
    }

    pub fn play_end(&self) -> bool {
        (self.status & 0b100000) == 0b100000
    }

    pub fn set_pause(&mut self) {
        println!("pause");
        self.status = self.status & 0b111110;
    }

    pub fn set_resume(&mut self) {
        println!("resume");
        self.status = self.status | 0b1;
    }

    pub fn set_packet_end(&mut self) {
        println!("packet end");
        self.status = self.status | 0b10;
    }

    pub fn set_audio_frame_end(&mut self) {
        println!("set audio");
        if self.status & 0b10 == 0b10 {
            println!("audio end");
            self.status = self.status | 0b100;
        }
    }
    
    pub fn set_video_frame_end(&mut self) {
        println!("set video");
        if self.status & 0b10 == 0b10 {
            println!("video end");
            self.status = self.status | 0b1000;
        }
    }

    pub fn forword(&mut self) {
        if self.status & 0b10000 == 0b10000 {
            self.status = self.status & 0b101111;
        } else {
            self.status = self.status | 0b10000;
        }
    }

    pub fn set_play_end(&mut self) {
        println!("end");
        self.status = self.status | 0b100000;
    }
}

// #[derive(Debug, Clone, PartialEq, Eq)]
// pub enum PlayStatus {
//     Start,
//     PacketEnd,
//     AudioFrameEnd,
//     VideoFrameEnd,
//     Pause,
//     Resume,
//     End,
// }

pub struct Packet {
    pub pkt: *mut AVPacket,
}

impl Packet {
    pub fn new() -> Packet {
        Packet {
            pkt: av_packet_alloc_safe(),
        }
    }
}

pub struct FormatContextSafe {
    pub av_format_context: *mut AVFormatContext,
}

unsafe impl Send for FormatContextSafe {}
unsafe impl Sync for FormatContextSafe {}

pub struct CodecContextSafe {
    pub av_codec_context: *mut AVCodecContext,
}
unsafe impl Send for CodecContextSafe {}
unsafe impl Sync for CodecContextSafe {}

pub struct VideoDevice {
    pub sdl: sdl2::Sdl,
    pub video_subsystem: VideoSubsystem,
}

unsafe impl Send for VideoDevice {}
unsafe impl Sync for VideoDevice {}


#[derive(Debug)]
pub struct PacketFifo {
    fifo: *mut AVFifo,
    size: usize,
}
unsafe impl Send for PacketFifo {}
unsafe impl Sync for PacketFifo {}

#[derive(Debug, Clone)]
pub struct SwrContextSafe {
    pub swr_context: *mut SwrContext,
}
unsafe impl Send for SwrContextSafe {}
unsafe impl Sync for SwrContextSafe {}

impl PacketFifo {
    pub fn new() -> Self {
        PacketFifo {
            fifo: av_fifo_alloc2_safe(
                1,
                size_of::<Packet>(),
                AV_FIFO_FLAG_AUTO_GROW as std::ffi::c_uint,
            ),
            size: 0,
        }
    }

    pub fn size(&self) -> usize {
        self.size
    }

    pub fn put_size(&mut self, size: usize) {
        self.size = size;
    }
}

#[derive(Debug, Default)]
pub struct VideoDecoderData {
    pub data: Vec<u8>,
    pub width: u32,
    pub height: u32,
    pub time: f64,
}

impl VideoDecoderData {
    pub fn new(data: Vec<u8>, width: u32, height: u32, time: f64) -> Self {
        VideoDecoderData {
            data,
            width,
            height,
            time,
        }
    }
}

#[derive(Debug, Clone)]
pub struct AudioDecoderData {
    pub data: Vec<u8>,
    pub audio_time: f64,
}

impl Default for AudioDecoderData {
    fn default() -> Self {
        Self {
            data: Vec::new(),
            audio_time: 0_f64,
        }
    }
}


